package org.qrd.openmayyam;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.qrd.openmayyam.Filter;


/**
 * Expand out a WAR file at a particular location.
 *
 * @author Adarsh 
 * @author Sivaraman
 * @version $Revision: 1.0.1 $
 */

public class ExpandWar {
	
	// ------------ Initialise variables
	
	/**
	 * The newlist contains the list of files that are listed on every check. 
	 * It includes the names of already extracted WAR files also.
	 * 
	 */
	
	File[] newlist;
	
	/**
	 * list contains the list of the WARs that are not present in the old list.
	 */
	
	File[] list;
	
	/**
	 * oldlist contains the list of WAR files that were previously extracted.
	 */
	
	File[] oldlist=null;
	
	/**
	 * Instance of the Filter class. It may be used to filter out WAR files.
	 */
	
	Filter filter;
	
	/**
	 * This variable contains the 
	 */
	
	File file;
	
	/**
	 * The constructor initialises the filter class with WAR extension.
	 */
	
	public ExpandWar(){
		
		filter=new Filter("war");
	}
		
	
/**
  * This method returns the string array containing a list of all the WAR files that have been expanded
  * 
  * @param warurl This parameter contains the complete path from where to listen for WAR files
  * 
  * If nothing is sent , "/home/adarsh/" is set as default   * 
  * 
  */
	
	public String[] expandAll(String warurl) throws IOException{
		String wars[] = new String[10];
		if(warurl.length()==0)
		warurl="/home/adarsh/";
		file=new File(warurl);
    	newlist=file.listFiles(filter);
    	
		String warfile="";
    	int period;
    	// Get the new files
    	
    	list=getnewfiles(oldlist,newlist);
    	// store this as a old list
    	
    	oldlist=newlist;
    	
    	System.out.println("old list");
    	
    	// if there are no new files
    	
    	if(list==null)	
    		return null;
    	
    	// Walk through the list of WAR files and expand them one by one  
    	
    	for (int i=0;i<list.length;i++) {
    		period=list[i].getName().toString().lastIndexOf(".");
    		warfile=list[i].getName().substring(0,period);
    		
    		// call the expand static method that expands the WAR file
    		
    		expand(list[i].toString(),warurl,warfile);
    		System.out.println("WAR File Expanded : " + warfile);
    	
    		// store the expanded WAR file in the string array
    		
    		wars[i]=warfile;
    	}
    	return wars;
	}

	/**
	 * Called by the expandAll() method to check for new WAR files
	 *   
	 * @param oldlist2 The old list of WAR files that were present on previous check
	 * @param newlist2 The list of WAR files that have obtained on this check
	 * 
	 * @return File array that contains the list of new files else null
	 */
	
	  private File[] getnewfiles(File[] oldlist2, File[] newlist2) {
		 
		  System.out.println("ExpandWar.getnewfiles()");
		  String oldlist,newlist;
		  int k=0,number=0;
		  int flag=0;
		  if(oldlist2==null)
			  return newlist2;
		  if(newlist2.length>oldlist2.length)
			  number=newlist2.length-oldlist2.length;
		  File[] list1=new File[number] ;
		  for(int i=0;i<newlist2.length;i++)
		  {
			  flag=0;
		
			  for(int j=0;j<oldlist2.length;j++)
			  {
				  // check if the file name is present in the old list
				  
				  if(oldlist2[j].getName().equals(newlist2[i].getName()))
				  {
					  flag=1;
					  break;
				  }
					  
			  }
			  // flag = 0 means that the file is a new one and not present in the old list
			  
			  if(flag==0)
			  {
				  System.out.println(newlist2[i].toString());
				  
				  // Add the WAR file name to the list 
				  
				  list1[k++]=newlist2[i];
			  }
				  
		  }
		 
		  return list1;
		  
	}

// -------- This method is not used .. just for testing purpose

	  /**
	   * This method may be used to test the application as a standalone application.
	   * The WAR file location is set as "/home/adarsh/sample.war" as default.
	   */
	  
	public static void main(String args[]) throws IOException
	    {
	    //	System.out.println("Please enter the complete WAR file location :  ");
	    	String warurl="/home/adarsh/sample.war";
	    	
	    //	String warurl=args[0];
	    	String warfile,pathname;
	    	int period; 
	        period = warurl.toString().lastIndexOf('/');
	        if(period==-1)
	    		period=warurl.toString().lastIndexOf("\\"); 
	        pathname = warurl.toString().substring(0, period+1);
	        warfile = warurl.toString().substring(period+1,warurl.toString().lastIndexOf("."));
	   //     System.out.println("period : " +period + " , pathname = "+pathname + " , war = "+ warfile);
	   //     expand(warurl,pathname,warfile);
	        new ExpandWar().expandAll(args[0]);
	    	
	    }
	/**
	 * Expands the given WAR file
	 * 
	 * @param warurl The complete location of the WAR file in the system. Eg. "/home/adarsh/sample.war"
	 * @param pathname The pathname of the WAR file to be expanded. Eg. "/home/adarsh/"
	 * @param warfile The name of the WAR file. Eg. "sample.war"
	 * 
	 * @throws IOException
	 */

     public static  void expand(String warurl,String pathname, String warfile)  throws IOException {;

          	
    	
        File docBase = new File(pathname,warfile);
        docBase.mkdir();
        JarFile jarFile = new JarFile(warurl);
        InputStream input = null;
        try {
         
            Enumeration jarEntries = jarFile.entries();
            while (jarEntries.hasMoreElements()) {
                JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
                String name = jarEntry.getName();
                int last = name.lastIndexOf('/');
                if (last >= 0) {
                    File parent = new File(docBase,
                                           name.substring(0, last));
                    parent.mkdirs();
                }
                if (name.endsWith("/")) {
                    continue;
                }
                input = jarFile.getInputStream(jarEntry);

                File expandedFile = expand(input, docBase, name);
                long lastModified = jarEntry.getTime();
                input.close();
                input = null;
            }
        } catch (IOException e) {
            // If something went wrong, delete expanded dir to keep things 
            // clean
            deleteDir(docBase);
            throw e;
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (Throwable t) {
                    ;
                }
                input = null;
            }
            if (jarFile != null) {
                try {
                    jarFile.close();
                } catch (Throwable t) {
                    ;
                }
                jarFile = null;
            }
        }

       return;

    }

     /**
      *  A dummy method to check the working of the expand method
      *  @param warurl It requires the WAR url. Eg. "/home/adarsh/sample.war".
      */

    public static void init(String warurl) throws IOException
    {
    //	System.out.println("Please enter the complete WAR file location :  ");
    	//String warurl="/home/adarsh/sample.war";
    //	String warurl=args[0];
    	String warfile,pathname;
    	int period; 
        period = warurl.toString().lastIndexOf('/');
        if(period==-1)
    		period=warurl.toString().lastIndexOf("\\"); 
        pathname = warurl.toString().substring(0, period+1);
        warfile = warurl.toString().substring(period+1,warurl.toString().lastIndexOf("."));
   //     System.out.println("period : " +period + " , pathname = "+pathname + " , war = "+ warfile);
        expand(warurl,pathname,warfile);
       
    	
    }
 
    
    /**
     * Delete the specified directory, including all of its contents and
     * subdirectories recursively.
     *
     * @param dir File object representing the directory to be deleted
     */
    public  boolean delete(File dir) {
        if (dir.isDirectory()) {
            return deleteDir(dir);
        } else {
            return dir.delete();
        }
    }
    
    
    /**
     * Delete the specified directory, including all of its contents and
     * subdirectories recursively.
     *
     * @param dir File object representing the directory to be deleted
     */
    public static  boolean deleteDir(File dir) {

        String files[] = dir.list();
        if (files == null) {
            files = new String[0];
        }
        for (int i = 0; i < files.length; i++) {
            File file = new File(dir, files[i]);
            if (file.isDirectory()) {
                deleteDir(file);
            } else {
                file.delete();
            }
        }
        return dir.delete();

    }


    /**
     * Expand the specified input stream into the specified directory, creating
     * a file named from the specified relative path.
     *
     * @param input InputStream to be copied
     * @param docBase Document base directory into which we are expanding
     * @param name Relative pathname of the file to be created
     * @return A handle to the expanded File
     *
     * @exception IOException if an input/output error occurs
     */
    protected static  File expand(InputStream input, File docBase, String name)
        throws IOException {

        File file = new File(docBase, name);
        BufferedOutputStream output = null;
        try {
            output = 
                new BufferedOutputStream(new FileOutputStream(file));
            byte buffer[] = new byte[2048];
            while (true) {
                int n = input.read(buffer);
                if (n <= 0)
                    break;
                output.write(buffer, 0, n);
            }
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }

        return file;
    }


}
